﻿using KPIS.GERP.WCF.ePayment.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Web.Script.Serialization;
using System.Web;

namespace KPIS.GERP.WCF.ePayment
{
    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        [WebInvoke(Method = "POST",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "/ws_send_request")
        ]
        string ws_send_request(SendArgument sendArgument);

        [OperationContract]
        [WebInvoke(Method = "POST",
            RequestFormat = WebMessageFormat.Json,
            ResponseFormat = WebMessageFormat.Json,
            UriTemplate = "/ws_send_result")
        ]
        string ws_send_result(SendArgument sendArgument);
    }



    public class Service : IService
    {
        public string strReturn = @"{{""transaction_ref"":""{0}"",""code"":""{1}"",""description"":""{2}"",""response_code"":""{3}"",""response_description"":""{4}"",""response_success"":""{5}"",""data"":""{6}""}}";
        JavaScriptSerializer jss = new JavaScriptSerializer();

        public string ws_send_request(SendArgument sendArgument)
        {
            string strExceptionCode = "";
            string strExceptionDescr = "";
            string strReturnData = "";
            string strData = "";

            try
            {
                CheckArgument(sendArgument);

                switch (sendArgument.process.ToUpper())
                {
                    case "CREATESUPPLIERINFO":
                        createSupplierInfo(sendArgument);
                        break;
                    case "CREATEVALIDATE":
                        strReturnData = createValidate(sendArgument) ? "{\"valid\":\"1\"}" : "{\"valid\":\"0\"}";
                        break;
                    case "CREATEINVOICE":
                        createInvoice(sendArgument);
                        break;
                    case "DELETEINVOICE":

                        break;
                    case "CREATEINQUIREPAYMENTSTATUS":
                        strReturnData = createInquirePaymentStatus(sendArgument);
                        break;
                    case "REJECTPAYMENT":

                        break;
                    default:
                        ExceptionHandler.GetException(ExceptionCode.E_InvalidProcess);
                        break;
                }
            }
            catch (Exception ex)
            {
                strExceptionCode = ex.InnerException == null ? "E_InternalError" : ex.Message;
                strExceptionDescr = ex.InnerException == null ? "An unrecoverable error occurred during processing the request." : ex.InnerException.Message;
            }

            strReturn = string.Format(strReturn, sendArgument.transaction_ref, "", "", strExceptionCode, strExceptionDescr, string.IsNullOrWhiteSpace(strExceptionCode) ? "1" : "-1", strReturnData);
            //strReturn = strReturn.Substring(1, strReturn.Length - 2);
            return strReturn;
        }

        public string ws_send_result(SendArgument sendArgument)
        {
            string strExceptionCode = "";
            string strExceptionDescr = "";
            string strReturnData = "";

            try
            {
                //Exception exCheckData = CheckArgument(sendArgument);

                //if (exCheckData == null)
                //{
                //    throw exCheckData;
                //}

                //switch (sendArgument.process)
                //{
                //    case "SupplierInfo":

                //        if (sendArgument.transaction_ref.Length > 10)
                //        {
                //            throw ExceptionHandler.GetException(ExceptionCode.E_TransactionId);
                //        }

                //        break;
                //    default:
                //        throw ExceptionHandler.GetException(ExceptionCode.E_TransactionId);
                //        break;
                //}
            }
            catch (Exception ex)
            {
                strExceptionCode = ex.InnerException == null ? "E_InternalError" : ex.Message;
                strExceptionDescr = ex.InnerException == null ? "An unrecoverable error occurred during processing the request." : ex.InnerException.Message;
            }

            strReturn = string.Format(strReturn, sendArgument.transaction_ref, "", "", strExceptionCode, strExceptionDescr, string.IsNullOrWhiteSpace(strExceptionCode) ? "1" : "-1", strReturnData);
            return strReturn;
        }

        public void CheckArgument(SendArgument sendArgument)
        {
            try
            {
                bool bOK = true;
                string strNullArgument = "";
                Exception ex = null;

                if (string.IsNullOrWhiteSpace(sendArgument.application_id))
                {
                    strNullArgument += " url ";
                }
                //else if (string.IsNullOrWhiteSpace(sendArgument.secret_code))
                //{
                //    strNullArgument += " secret_code ";
                //}
                else if (string.IsNullOrWhiteSpace(sendArgument.transaction_ref))
                {
                    strNullArgument += " transaction_ref ";
                }
                else if (string.IsNullOrWhiteSpace(sendArgument.process))
                {
                    strNullArgument += " process ";
                }
                else if (!CheckProcessName(sendArgument.process))
                {
                    strNullArgument = "";
                    ExceptionHandler.GetException(ExceptionCode.E_InvalidProcess);
                }

                if (!string.IsNullOrWhiteSpace(strNullArgument))
                {
                    ExceptionHandler.GetException(ExceptionCode.E_ArgumentsValidation, strNullArgument);
                    //ex.Message += strNullArgument;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public bool CheckProcessName(string ProcessName)
        {
            switch (ProcessName.ToUpper())
            {
                case "CREATESUPPLIERINFO":
                case "CREATEVALIDATE":
                case "CREATEINVOICE":
                case "DELETEINVOICE":
                case "CREATEINQUIREPAYMENTSTATUS":
                case "REJECTPAYMENT":
                    return true;
                default:
                    return false;
            }
        }

        private void createSupplierInfo(SendArgument sendArgument)
        {
            try
            {
                string strData = HttpUtility.HtmlDecode(sendArgument.data);
                Supplier supplier = jss.Deserialize<Supplier>(strData);
                Supplier model = null;

                using (ePaymentContext context = new ePaymentContext())
                {
                    model = context.Suppliers.Where(m => !m.deleted).Where(m => m.supplier_tax_code == supplier.supplier_tax_code).FirstOrDefault();
                }

                if (model == null)
                {
                    supplier.Create(supplier);
                }
                else
                {
                    model.supplier_tax_code = supplier.supplier_tax_code;
                    model.supplier_branch_code = supplier.supplier_branch_code;
                    model.supplier_name = supplier.supplier_name;
                    model.business_type = supplier.business_type;
                    model.bank_account_code = supplier.bank_account_code;
                    model.address = supplier.address;
                    model.tel = supplier.tel;
                    model.fax = supplier.fax;
                    supplier.Edit(model);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool createValidate(SendArgument sendArgument)
        {
            try
            {
                bool bOK = true;
                string strData = sendArgument.data;
                ValidateData validateData = jss.Deserialize<ValidateData>(strData);

                switch (validateData.validate_type)
                {
                    case "1":
                        bOK = validateData.data_code.Length != 13;

                        break;
                    case "2":
                        bOK = validateData.data_code.Length != 10;

                        break;
                    case "3":
                        bOK = validateData.data_code.Length != 13;

                        break;
                    default:
                        ExceptionHandler.GetException(ExceptionCode.E_ArgumentsValidation, "validate_type");
                        break;
                }

                return bOK;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void createInvoice(SendArgument sendArgument)
        {
            try
            {
                string strData = sendArgument.data;
                createInvoice data = jss.Deserialize<createInvoice>(strData);
                Invoice invoice = null;
                Supplier supplier = null;

                using (ePaymentContext context = new ePaymentContext())
                {
                    supplier = context.Suppliers.Where(m => !m.deleted).Where(m => m.supplier_tax_code == data.supplier_tax_code).FirstOrDefault();
                    invoice = context.Invoices.Where(m => !m.deleted).Where(m => m.invoice_code == data.invoice_code && m.supplier_id == supplier.supplier_id).FirstOrDefault();
                    
                }

                if (supplier == null)
                {
                    ExceptionHandler.GetException(ExceptionCode.E_InvalidSupplier, data.supplier_tax_code);
                }


                if (invoice == null)
                {
                    DateTime InvoiceDate;
                    
                    if (!DateTime.TryParse(data.date, out InvoiceDate))
                    {
                        ExceptionHandler.GetException(ExceptionCode.E_IncorrectDate);
                    }

                    invoice = new Invoice()
                    {
                        invoice_code = data.invoice_code,
                        po_code = data.po_code,
                        lot_no = data.lot_no,
                        date = InvoiceDate.AddYears(543),
                        supplier_id = supplier.supplier_id,
                        doc_id = data.doc_id,
                    };
                    int invoice_id = invoice.Create(invoice);

                    foreach (createInvoiceItem dataitem in data.item)
                    {
                        double dQty;
                        double dExcludeVatPrice;
                        double dIncludeVatPrice;
                        double dVatAmount;
                        double dDiscountAmount;
                        double dExcludeVatAmount;
                        double dIncludeVatAmount;

                        if (!double.TryParse(dataitem.qty, out dQty))
                        {
                            ExceptionHandler.GetException(ExceptionCode.E_IncorrectNumeric);
                        }
                        if (!double.TryParse(dataitem.exclude_vat_price, out dExcludeVatPrice))
                        {
                            ExceptionHandler.GetException(ExceptionCode.E_IncorrectNumeric);
                        }
                        if (!double.TryParse(dataitem.include_vat_price, out dIncludeVatPrice))
                        {
                            ExceptionHandler.GetException(ExceptionCode.E_IncorrectNumeric);
                        }
                        if (!double.TryParse(dataitem.vat_amount, out dVatAmount))
                        {
                            ExceptionHandler.GetException(ExceptionCode.E_IncorrectNumeric);
                        }
                        if (!double.TryParse(dataitem.discount_amount, out dDiscountAmount))
                        {
                            ExceptionHandler.GetException(ExceptionCode.E_IncorrectNumeric);
                        }
                        if (!double.TryParse(dataitem.exclude_vat_amount, out dExcludeVatAmount))
                        {
                            ExceptionHandler.GetException(ExceptionCode.E_IncorrectNumeric);
                        }
                        if (!double.TryParse(dataitem.include_vat_amount, out dIncludeVatAmount))
                        {
                            ExceptionHandler.GetException(ExceptionCode.E_IncorrectNumeric);
                        }

                        InvoiceItem item = new InvoiceItem()
                        {
                            invoice_id = invoice_id,
                            product_id = null,
                            product_code = dataitem.product_code,
                            product_name = dataitem.product_name,
                            qty = dQty,
                            exclude_vat_price = dExcludeVatPrice,
                            include_vat_price = dIncludeVatPrice,
                            vat_amount = dVatAmount,
                            discount_amount = dDiscountAmount,
                            exclude_vat_amount = dExcludeVatAmount,
                            include_vat_amount = dIncludeVatAmount,
                            unit = dataitem.unit,
                            remark_1 = dataitem.remark_1,
                            doc_id = dataitem.doc_id,
                        };

                        item.Create(item);
                    }
                }
                else
                {
                    ExceptionHandler.GetException(ExceptionCode.E_DuplicateInvoice, invoice.invoice_code);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private string createInquirePaymentStatus(SendArgument sendArgument)
        {
            try
            {
                string strData = sendArgument.data;
                string strReturn = "";
                InquirePaymentStatus inquirePaymentStatus = jss.Deserialize<InquirePaymentStatus>(strData);
                bool bOK = !(inquirePaymentStatus.invoice_code.Length > 10);

                if (bOK)
                {
                    PaymentStatus paymentStatus = new PaymentStatus()
                    {
                        doc_id = inquirePaymentStatus.doc_id,
                        g_office_code = inquirePaymentStatus.g_office_code,
                        invoice_code = inquirePaymentStatus.invoice_code,
                        invoice_status = new Random().Next(1, 5).ToString(),
                    };
                    strReturn = new JavaScriptSerializer().Serialize(paymentStatus);
                }
                else
                {
                    throw new Exception();
                }

                return strReturn;
            }
            catch
            {
                throw new Exception();
            }
        }
    }
    

    [DataContract]
    public class SendArgument
    {
        [DataMember]
        public string application_id { get; set; }
        [DataMember] 
        public string secret_code { get; set; }
        [DataMember] 
        public string transaction_ref { get; set; }
        [DataMember] 
        public string return_url { get; set; }
        [DataMember] 
        public string process { get; set; }
        [DataMember] 
        public string data { get; set; }
    }

    public class ValidateData
    {
        public string g_office_code { get; set; }
        public string validate_type { get; set; }
        public string data_code { get; set; }

    }

    public class createInvoice
    {
        public string invoice_code { get; set; }
        public string po_code { get; set; }
        public string lot_no { get; set; }
        public string date { get; set; }
        public string supplier_tax_code { get; set; }
        public string g_office_code { get; set; }
        public string doc_id { get; set; }

        public List<createInvoiceItem> item { get; set; }
    }

    public class createInvoiceItem
    {
        public string product_code { get; set; }
        public string product_name { get; set; }
        public string qty { get; set; }
        public string exclude_vat_price { get; set; }
        public string include_vat_price { get; set; }
        public string vat_amount { get; set; }
        public string discount_amount { get; set; }
        public string exclude_vat_amount { get; set; }
        public string include_vat_amount { get; set; }
        public string unit { get; set; }
        public string remark_1 { get; set; }
        public string doc_id { get; set; }
    }

    public class InquirePaymentStatus
    {
        public string supplier_tax_code { get; set; }
        public string invoice_code { get; set; }
        public string doc_id { get; set; }
        public string g_office_code { get; set; }
    }

    public class PaymentStatus
    {
        public string invoice_code { get; set; }
        public string doc_id { get; set; }
        public string g_office_code { get; set; }
        public string invoice_status { get; set; }
    }

    public enum Processes
    {
        createSupplierInfo
    }
}
